#include <iostream>

// int add(int a, int b)
// {
//     return a + b;
// }

// double add(double a, double b)
// {
//     return a + b;
// }

// 模板函数
// 模板关键字template，声明一个模板
// <>里面是参数定义，typename声明一个模板变量T
template <typename T>
T add(T a, T b)
{
    std::cout << "add(T, T)" << std::endl;
    return a + b;
}

template <typename T>
void Swap(T &a, T &b)
{
    T temp = a;
    a = b;
    b = temp;
}

int add(int a, int b)
{
    std::cout << "add(int, int)" << std::endl;
    return a + b;
}

int main()
{
#if 0
    // 模板的显式调用
    std::cout << add<int>(1, 2) << std::endl;

    // 模板的隐式调用
    // 模板的类型推导：编译器自动推导模板的数据类型
    std::cout << add(1.1, 2.2) << std::endl;
#endif

#if 0
    int a = 10;
    int b = 20;
    Swap(a, b);
    std::cout << a << " " << b << std::endl;
#endif

#if 0
    char a = 'A';
    char b = 'B';
    Swap(a, b);
    std::cout << a << " " << b << std::endl;
#endif

#if 1
// 模板函数匹配的规则：
    // 1、普通函数遇上模板函数优先调用普通函数
    std::cout << add(1, 2) << std::endl;
    // 2、如果模板函数具有更好的类型匹配，优先模板函数
    std::cout << add(1.0, 2.0) << std::endl;
    // 3、普通函数的数据类型具有隐式转换能力，而模板的类型必须严格匹配，不能隐式转换
    std::cout << add(1, 'a') << std::endl;
    // 如果没有自定义int类型的add函数，种写法是错误的
    // 但如果自定义了int类型的add函数，则编译能通过，并且会发生隐式转换，将'a'转换成int类型
#endif

    return 0;
}